#include <stdlib.h>
#include "Arbre.h"
#include "Symbole.h"
#include "SymboleValue.h"
#include "NoeudVisitor.h"


AfficherVisitor::AfficherVisitor() : NoeudVisitor()
{
    indentation =0;    //
}
//    virtual ~NoeudVisitor();
void AfficherVisitor::VisitNoeudProg ( NoeudProg* )
{
    afficherIndentation();
    cout << "Le programme : " << endl;
}
void AfficherVisitor::VisitNoeudSeqInst ( NoeudSeqInst* e )
{
    afficherIndentation();
    cout << "Noeud - Sequence de " << e->getSize() << " instruction(s)" << endl;
}
void AfficherVisitor::VisitNoeudSeqDecl ( NoeudSeqDecl* e )
{
    afficherIndentation();
    cout << "Noeud - Sequence de " << e->getSize() << " declaration(s)" << endl;
}
void AfficherVisitor::VisitNoeudPour ( NoeudPour* )
{
    afficherIndentation();
    cout << "Noeud - Pour" << endl;
}
void AfficherVisitor::VisitNoeudSi ( NoeudSi* )
{
    afficherIndentation();
    cout << "Noeud - Si" << endl;
}
void AfficherVisitor::VisitNoeudTantQue ( NoeudTantQue* )
{
    afficherIndentation();
    cout << "Noeud - TantQue" << endl;
}
void AfficherVisitor::VisitNoeudRepeter ( NoeudRepeter* )
{
    afficherIndentation();
    cout << "Noeud - Repeter" << endl;
}
void AfficherVisitor::VisitNoeudAffectation ( NoeudAffectation* )
{
    afficherIndentation();
    cout << "Noeud - Affectation" << endl;
}
void AfficherVisitor::VisitNoeudAffectationPour ( NoeudAffectationPour* e )
{
    VisitNoeudAffectation((NoeudAffectation*)e);
}
void AfficherVisitor::VisitNoeudDeclaration ( NoeudDeclaration* e )
{
    afficherIndentation();
    cout << "Noeud - Declaration \"" << e->getType().getChaine() << "\" : " << endl;
}
void AfficherVisitor::VisitNoeudEcrire ( NoeudEcrire* )
{
    afficherIndentation();
    cout << "Noeud - Ecrire" << endl;
}
void AfficherVisitor::VisitNoeudLire ( NoeudLire* )
{
    afficherIndentation();
    cout << "Noeud - Lire" << endl;
}
void AfficherVisitor::VisitNoeudOperateurBinaire ( NoeudOperateurBinaire* e )
{
    afficherIndentation();
    cout << "Noeud - Operateur Binaire \"" << e->getOperateur().getChaine() << "\" applique a : " << endl;
}
void AfficherVisitor::VisitSymboleValue ( SymboleValue* e )
{
    afficherIndentation();
    cout << "Feuille - Symbole value : " << e->getChaine() << endl;
}




TypeVisitor::TypeVisitor() : NoeudVisitor()
{
    nbErreur = 0;
}
void TypeVisitor::VisitNoeudProg ( NoeudProg* )
{
}
void TypeVisitor::VisitNoeudSeqInst ( NoeudSeqInst* )
{
}
void TypeVisitor::VisitNoeudSeqDecl ( NoeudSeqDecl* )
{
}
void TypeVisitor::VisitNoeudPour ( NoeudPour* )
{
}
void TypeVisitor::VisitNoeudSi ( NoeudSi* )
{
}
void TypeVisitor::VisitNoeudTantQue ( NoeudTantQue* )
{
}
void TypeVisitor::VisitNoeudRepeter ( NoeudRepeter* )
{
}
void TypeVisitor::VisitNoeudAffectation ( NoeudAffectation* e )
{
    if ( ( ((SymboleValue*)e->getVariable())->SymboleValue::getType() == ENTIER ) && (( typeid ( *e->getExpression()->getValeur() ) != typeid ( ValeurFloat ) )&& ( typeid ( *e->getExpression()->getValeur() ) != typeid ( ValeurInt ) ) )) {
        erreurTypAffect(e," on ne peut affecter a une variable de type ENTIER qu'un entier ou un reel (cast)." );
    }
    if ( (( (SymboleValue*)e->getVariable())->SymboleValue::getType() == REEL ) && (( typeid ( *e->getExpression()->getValeur() ) != typeid ( ValeurFloat ) ) && ( typeid ( *e->getExpression()->getValeur() ) != typeid ( ValeurInt ) ) ))  {
        erreurTypAffect(e," on ne peut affecter a une variable de type REEL qu'un reel ou un entier (cast)." );
    }
    if ( (( (SymboleValue*)e->getVariable())->SymboleValue::getType() == CHAINE ) && ( typeid ( *e->getExpression()->getValeur() ) != typeid ( ValeurString ) ) ) {
        erreurTypAffect(e," on ne peut affecter a une variable de type CHAINE qu'une chaine." );
    }
    if ( (( (SymboleValue*)e->getVariable())->SymboleValue::getType() == CHAR ) && ( typeid ( *e->getExpression()->getValeur() ) != typeid ( ValeurChar ) ) ) {
        erreurTypAffect(e," on ne peut affecter a une variable de type CARACT qu'un caractere." );
    }
}
void TypeVisitor::VisitNoeudAffectationPour ( NoeudAffectationPour* e )
{
    VisitNoeudAffectation((NoeudAffectation*)e);
}
void TypeVisitor::VisitNoeudDeclaration ( NoeudDeclaration* )
{
}
void TypeVisitor::VisitNoeudEcrire ( NoeudEcrire* )
{

}
void TypeVisitor::VisitNoeudLire ( NoeudLire* )
{


}
void TypeVisitor::VisitNoeudOperateurBinaire ( NoeudOperateurBinaire* e )
{
    try {
        if ( ( e->getOperateur() == "+" ) || ( e->getOperateur() == "-" )  || ( e->getOperateur() == "*" )  || ( e->getOperateur() == "/" ) )
        {
            if ( ( typeid ( *e->getOperandeGauche()->getValeur() ) == typeid ( ValeurInt ) ) && (( typeid (*e->getOperandeDroit()->getValeur() ) != typeid ( ValeurFloat ) ) && ( typeid (*e->getOperandeDroit()->getValeur() ) != typeid ( ValeurInt ) )) ) {
                erreurTypage(e,"Operation arithmetique authorise seulement entre entier et/ou reel. ");
            }
            else if ( ( typeid (*e->getOperandeGauche()->getValeur() ) == typeid ( ValeurFloat ) ) && (( typeid (*e->getOperandeDroit()->getValeur() ) != typeid ( ValeurFloat ) ) && ( typeid (*e->getOperandeDroit()->getValeur() ) != typeid ( ValeurInt ) )) ) {
                erreurTypage(e,"Operation arithmetique authorise seulement entre entier et/ou reel. ");
            }
            if ( ( typeid (*e->getOperandeGauche()->getValeur() ) == typeid ( ValeurString ) ) || ( typeid (*e->getOperandeDroit()->getValeur() ) == typeid ( ValeurString ) ) ) {
                erreurTypage(e,"Operation arithmetique authorise seulement entre entier et entre reel. ");
            }
            if ( ( typeid (*e->getOperandeGauche()->getValeur() ) == typeid ( ValeurChar ) ) || ( typeid (*e->getOperandeDroit()->getValeur() ) == typeid ( ValeurChar ) ) ) {
                erreurTypage(e,"Operation arithmetique authorise seulement entre entier et entre reel. ");
            }
        }
        if ( ( e->getOperateur() == "==" ) || ( e->getOperateur() == "!=" ) || ( e->getOperateur() == "<=" )
                || ( e->getOperateur() == "<" ) || ( e->getOperateur() == ">=" ) || ( e->getOperateur() == ">" ) ) {
            if ( ( typeid ( *e->getOperandeGauche()->getValeur() ) == typeid ( ValeurInt ) ) && ( typeid (*e->getOperandeDroit()->getValeur() ) != typeid ( ValeurInt ) ) ) {
                erreurTypage(e,"Operation arithmetique authorise seulement entre entier et entre reel. ");
            }
            else if ( ( typeid (*e->getOperandeGauche()->getValeur() ) == typeid ( ValeurFloat ) ) && ( typeid ( *e->getOperandeDroit()->getValeur() ) != typeid ( ValeurFloat ) ) ) {
                erreurTypage(e,"Operation arithmetique authorise seulement entre entier et entre reel. ");
            }
            if ( ( typeid (*e->getOperandeGauche()->getValeur() ) == typeid ( ValeurString ) ) || ( typeid (*e->getOperandeDroit()->getValeur() ) == typeid ( ValeurString ) ) ) {
                erreurTypage(e,"Operation arithmetique authorise seulement entre entier et entre reel. ");
            }
            if ( ( typeid (*e->getOperandeGauche()->getValeur() ) == typeid ( ValeurChar ) ) || ( typeid (*e->getOperandeDroit()->getValeur() ) == typeid ( ValeurChar ) ) ) {
                erreurTypage(e,"Operation arithmetique authorise seulement entre entier et entre reel. ");
            }
        }
    }
    catch (char const*) {
        throw;
    }
}
void TypeVisitor::VisitSymboleValue ( SymboleValue* )
{

}

void TypeVisitor::erreurTypage (NoeudOperateurBinaire* e, string mess) {
    try {
        cout << endl << "-------- Erreur de Typage - ligne : " << ((SymboleValue*)e->getOperandeDroit())->getLigne() << endl
             << "   " << mess << " ici : " << ((SymboleValue*)e->getOperandeDroit())->getChaine() << " et " << ((SymboleValue*)e->getOperandeGauche())->getChaine()  << endl << endl;
        throw "erreur typage";
    }
    catch (char const*) {
        throw;
    }
}

void TypeVisitor::erreurTypAffect(NoeudAffectation* e, string mess) {
    try {
        cout << endl << "-------- Erreur de Typage dans une affectation - ligne : " << ((SymboleValue*)e->getVariable())->getLigne() << endl
             << "   " << mess << " ici : " << ((SymboleValue*)e->getVariable())->getChaine() << " à " << ((SymboleValue*)e->getExpression())->getChaine() << endl << endl;
        throw "erreur affectation";
    }
    catch (char const*) {
        throw;
    }
}




ConversionVisitor::ConversionVisitor() : NoeudVisitor()
{
    indentation =0;
}
void ConversionVisitor::VisitNoeudProg ( NoeudProg*)
{

    //   afficherIndentation();
    cout << "#include <iostream>" << endl;
    cout << "#include <iomanip>" << endl;
    cout << "using namespace std;" << endl;
    cout << endl << endl;
    cout << "int main ( int argc, char** argv ) {";
//     IncresIndentation();
//     cout << "// Les Declarations";
//    ((NoeudProg*)e)->getDecl()->Accept(&this);
//     cout << endl << endl;
//     cout << "// Les Instructions";
//    ((NoeudProg*)e)->getinst()->Accept((NoeudVisitor*)this);
//    DecresIndentation();
//    cout << endl << "}" << endl;

}
void ConversionVisitor::VisitNoeudSeqInst ( NoeudSeqInst* )
{
}
void ConversionVisitor::VisitNoeudSeqDecl ( NoeudSeqDecl* )
{
}
void ConversionVisitor::VisitNoeudPour ( NoeudPour*)
{
    cout << "for (";
}
void ConversionVisitor::VisitNoeudSi ( NoeudSi* ) //(SymboleValue*)
{
    cout << "if (";
}
void ConversionVisitor::VisitNoeudTantQue ( NoeudTantQue* )
{
    cout << "while (";

}
void ConversionVisitor::VisitNoeudRepeter ( NoeudRepeter* )
{
    cout << "while (";
}
void ConversionVisitor::VisitNoeudAffectation ( NoeudAffectation* )
{
}
void ConversionVisitor::VisitNoeudAffectationPour ( NoeudAffectationPour* )
{
}
void ConversionVisitor::VisitNoeudDeclaration ( NoeudDeclaration* )
{
}
void ConversionVisitor::VisitNoeudEcrire ( NoeudEcrire* )
{
    cout << "cout << ";
}
void ConversionVisitor::VisitNoeudLire ( NoeudLire* )
{
    cout << "cin >> ";
}
void ConversionVisitor::VisitNoeudOperateurBinaire ( NoeudOperateurBinaire* )
{
}
void ConversionVisitor::VisitSymboleValue ( SymboleValue* e)
{
    cout << ((SymboleValue*)e)->getChaine();
}

void ConversionVisitor::afficherType(string type) {
    if (type == ENTIER)
        cout << "int";
    if (type == REEL)
        cout << "float";
    if (type == CHAINE)
        cout << "string";
    if (type == CHAR)
        cout << "char";
}

void ConversionVisitor::afficherOp(string op) {
    if (op == ET)
        cout << " && ";
    else if (op == OU)
        cout << " || ";
    else
    	cout << op;
}

